/*
 * UWT May 2014
 */
package controller;

import java.awt.Color;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

import javax.swing.JComponent;

import model.HeatMap;
import model.HeatMapCluster;
import model.HeatMapData;
import net.sf.javaml.clustering.Clusterer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import view.ClusterListPanel;
import view.DatabasePanel;
import view.VisualCandoGUI;
import database.CandoDatabase;

/**
 * Controls for VisualCando application.
 * 
 * @author Matt Adams
 */
public class VisualCandoControls implements Controls {
	private static final Logger logger = LoggerFactory.getLogger(VisualCandoControls.class);
	
	private String heatMapDataDirectory;
	private String heatMapImageDirectory;
	
	/**
	 * Database connection.
	 */
    private CandoDatabase database;
    
    /**
     * GUI for application.
     */
    private VisualCandoGUI view;
    
    /**
     * Constructs VisualCandoControls object.
     */
    public VisualCandoControls() {
    	loadProperties();
        this.view = new VisualCandoGUI(this);
        this.database = new CandoDatabase(this);

    }
    
    /* (non-Javadoc)
     * @see controller.Controls#start()
     */
    @Override
    public void start() {
        this.view.createInitialView();
    }
    
	@Override
	public void startDatabaseGUI() {
		this.view.createDatabaseGUIView(new DatabasePanel(this.database));	
	}

    /* (non-Javadoc)
     * @see controller.Controls#generateHeatMap(org.tc33.jheatchart.HeatChart)
     */
    @Override
    public void generateHeatMap(final String[] compoundNames, final String[] proteinIDs) {
    	
    	generateHeatMap(compoundNames, proteinIDs, null, null);
    }
    
	@Override
	public void generateHeatMap(final String[] compoundNames, 
								final String[] proteinIDs, 
								final Clusterer kMeansPro,
								final Clusterer kMeansComp) {
		try {
			this.database.processQuery(compoundNames, proteinIDs);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		final double[][] data = this.database.getData();
		final Object[] xValues = this.database.getCompounds();
		final Object[] yValues = this.database.getProteins();
		
		final HeatMapData heatMapData = new HeatMapData(data, xValues, yValues);
		HeatMapCluster  clusteredMap = null;

		if (kMeansPro != null && kMeansComp != null) {
			logger.info("Initiating clustering by proteins and followed by compounds.");
			clusteredMap = new HeatMapCluster(heatMapData, kMeansPro, kMeansComp);
		} else if (kMeansPro != null) {
			logger.info("Initiating clustering by proteins.");
			clusteredMap = new HeatMapCluster(heatMapData, kMeansPro, null);
		} else if (kMeansComp != null) {
			logger.info("Initiating clustering by compounds.");
			clusteredMap = new HeatMapCluster(heatMapData, null, kMeansComp);
		}
		if (clusteredMap != null) {
			logger.info("Clustered heat map success.");
			launchClusterListPanel(clusteredMap);
		} else {
			logger.info("No clustering selected. Generating heat map...");
			launchClusterListPanel(new HeatMapCluster(heatMapData, null, null));
		}	
	}
	

	
	@Override
	public String saveHeatMapToFile(final HeatMapData heatMapData, final String name) {
		heatMapData.setLowColor(this.view.getLowColor());
		heatMapData.setHighColor(this.view.getHighColor());
		logger.warn("Data height: {}", heatMapData.getData().length);
		logger.warn("Data width: {}", heatMapData.getData()[0].length);
		final HeatMap map = new HeatMap(heatMapData);
		final String timestampTag = new SimpleDateFormat("yyyy-MM-dd-hh-mm-SSS").format(new Date());
		final String imageFileName = this.heatMapImageDirectory + "/" + name + "_" + timestampTag + ".png";
		final String dataFileName = this.heatMapDataDirectory + "/" + name + "_" + timestampTag + ".csv";
		map.saveImageToFile(imageFileName);
		heatMapData.saveDataToFile(dataFileName);
		return imageFileName;		
	}
	
	@Override
	public void displayErrorMessage(String errorMessage) {
		this.view.displayErrorMessage(errorMessage);
		
	}
	
	@Override
	public void setDefaultColors(Color lowColor, Color highColor) {
		//Set new values in properties file
		final Properties prop = new Properties();
		OutputStream output = null;
	 
		try {	
			output = new FileOutputStream("color.properties"); 
			// set the properties value
			prop.setProperty("color.low", Integer.toString(lowColor.getRGB(), 16));
			prop.setProperty("color.high", Integer.toString(highColor.getRGB(), 16));
	 
			// save properties to project root folder
			prop.store(output, null);
	 
		} catch (IOException io) {
			io.printStackTrace();
		} finally {
			if (output != null) {
				try {
					output.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
	 
		}
		
	}

	@Override
	public void updateView() {
		this.view.updateView();
	}
	
	@Override
	public void displayProgressBar() {
		this.view.launchWaitDialog();	
	}
	
	@Override
	public void closeProgressBar() {
		this.view.closeWaitDialog();		
	}
	
	private void launchClusterListPanel(final HeatMapCluster clusteredMap) {
		this.view.launchNewFrame("Heat Map Clusters", 
								 new ClusterListPanel(this, clusteredMap.getRankedClusters(), 
							     "Cluster Ranking by Signal (high to low)"));		
	}
	
	@Override
	public void displayHeatMapImage(final String title, final JComponent displayComponent) {
		this.view.launchHeatMapImageDialog(title, displayComponent);		
	}
	
	private void loadProperties() {
    	final Properties prop = new Properties();
    	InputStream input = null;   
    	try {    
    		input = new FileInputStream("gui.properties");
    		//load directories
    		prop.load(input);
    		this.heatMapDataDirectory = prop.getProperty("heat_map_data_directory");
    		this.heatMapImageDirectory = prop.getProperty("heat_map_image_directory");

    	} catch (IOException ex) {
    		ex.printStackTrace();
    	} finally {
    		if (input != null) {
    			try {
    				input.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    	}
	}
}
